package com.kedou.sdk.requester;

import android.accounts.NetworkErrorException;
import android.content.Context;
import android.net.Uri;
import android.text.TextUtils;

import com.kedou.sdk.core.HttpEngineApi;
import com.kedou.sdk.params.PostRequestParams;
import com.kedou.sdk.utils.IoUtils;
import com.kedou.sdk.utils.NetworkUtils;
import com.kedou.sdk.utils.WL;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;

/**
 * Created by Administrator on 2017/5/27 0027.
 */

public class BaseHttpRequester implements HttpRequester {

    private static final String TAG = BaseHttpRequester.class.getSimpleName();

    public static final int DEFAULT_HTTP_CONNECT_TIMEOUT = 5 * 1000; // milliseconds

    public static final int DEFAULT_HTTP_READ_TIMEOUT = 20 * 1000; // milliseconds

    protected static final String ALLOWED_URI_CHARS = "@#&=*+-_.,:!?()/~'%";

    private static final int MAX_REDIRECT_COUNT = 5;

    protected final Context context;
    protected final int connectTimeout;
    protected final int readTimeout;

    public BaseHttpRequester(Context context) {
        this(context, DEFAULT_HTTP_CONNECT_TIMEOUT, DEFAULT_HTTP_READ_TIMEOUT);
    }

    public BaseHttpRequester(Context context, int connectTimeout, int readTimeout) {
        this.context = context.getApplicationContext();
        this.connectTimeout = connectTimeout;
        this.readTimeout = readTimeout;
    }

    @Override
    public InputStream getInputStream(String url, Method httpMethod, PostRequestParams requestParams) throws NetworkErrorException, IOException {
        if (!NetworkUtils.isConnectedByState(context)) {
            throw new NetworkErrorException("The device doesn't currently have access to the network.");
        }
        return getStreamFromNetwork(url, httpMethod, requestParams);
    }

    protected InputStream getStreamFromNetwork(String url, Method httpMethod, PostRequestParams requestParams) throws IOException {
        HttpURLConnection conn = createConnection(url, httpMethod, requestParams);

        int redirectCount = 0;
        while (conn.getResponseCode() / 100 == 3 && redirectCount < MAX_REDIRECT_COUNT) {
            conn = createConnection(conn.getHeaderField("Location"), httpMethod, requestParams);
            redirectCount++;
        }

        InputStream inputStream;
        try {
            inputStream = conn.getInputStream();
        } catch (IOException e) {
            // Read all data to allow reuse connection
            IoUtils.readAndCloseStream(conn.getErrorStream());
            throw e;
        }

        if (!shouldBeProcessed(conn)) {
            IoUtils.closeSilently(inputStream);
            throw new IOException("WanSDK request failed with response code " + conn.getResponseCode());
        }

        return inputStream;
    }

    protected HttpURLConnection createConnection(String url, Method httpMethod, PostRequestParams requestParams) throws IOException {
        String encodedUrl = Uri.encode(url, ALLOWED_URI_CHARS);
        WL.d(TAG, "Http request url: " + encodedUrl);
        HttpURLConnection conn = (HttpURLConnection) new URL(encodedUrl).openConnection();
        conn.setConnectTimeout(connectTimeout);
        conn.setReadTimeout(readTimeout);
        conn.setRequestProperty("content-type", "application/json; charset=utf-8");
        conn.setRequestProperty("authorization", "Bearer "+ HttpEngineApi.getInstance().getEngineConduits().readCurrentLoginUserTicket());

        conn.setUseCaches(false);
        createRequestMethod(conn, httpMethod, requestParams);
        return conn;

    }

    protected void createRequestMethod(HttpURLConnection conn, Method httpMethod, PostRequestParams requestParams) {
        if (Method.POST == httpMethod) {
            post(conn, requestParams);
        } else if (Method.GET == httpMethod) {
            get(conn);
        } else {
            WL.w(TAG, "This HTTP method doesn't support");
        }
    }


    protected void post(HttpURLConnection conn, PostRequestParams requestParams) {
        OutputStream outputStream = null;
        try {
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestMethod(Method.POST.name());
            String reqStr = requestParams.toParamsString();

            WL.d(TAG, "http post data: " + reqStr);

            if (!TextUtils.isEmpty(reqStr)) {
                outputStream = conn.getOutputStream();
                outputStream.write(reqStr.getBytes("UTF-8"));
                outputStream.flush();
            }
        } catch (ProtocolException e) {
            WL.e(TAG, "Invalid HTTP method: " + Method.POST.name());
        } catch (UnsupportedEncodingException e) {
            WL.e(TAG, "Unsupported Encoding Exception");
        } catch (IOException e) {
            WL.e(TAG, "protocol doesn't support output: " + e.getLocalizedMessage());
        } finally {
            IoUtils.closeSilently(outputStream);
        }

    }

    protected void get(HttpURLConnection conn) {
        try {
            conn.setDoInput(true);
            conn.setRequestMethod(Method.GET.name());
        } catch (ProtocolException e) {
            WL.e(TAG, "Invalid HTTP method: " + Method.GET.name());
        }
    }

    protected boolean shouldBeProcessed(HttpURLConnection conn) throws IOException {
        return conn.getResponseCode() == HttpURLConnection.HTTP_OK;
    }

}
